#if !defined(ximera_net_socket_hpp)
#define ximera_net_socket_hpp

// -----------------------------------------------------------

#include <ximera/net/address.hpp>
#include <ximera/exception.hpp>

namespace ximera { namespace net
{
    XIMERA_ENUM(ProtocolType)
        Tcp,
        Udp
    XIMERA_ENUM_END(ProtocolType)

#if defined(XIMERA_WIN32)
    typedef unsigned int SocketHandle;
#endif

    XIMERA_DECLARE_EXCEPTION(SocketException, L"Socket Exception");

    class XIMERA_API Socket
    {
    public:
        explicit Socket(ProtocolType protocol = ProtocolType::Tcp);
        ~Socket();

        bool blocking() const;
        void blocking(bool value);

        UInt32 receiveTimeout() const;
        void receiveTimeout(UInt32 value);

        bool connected() const;
        bool bound() const;
        bool available() const;

        IPEndPoint const& localEndPoint() const;
        IPEndPoint const& remoteEndPoint() const;

        void connect(IPEndPoint const& endpoint);
        void disconnect();
        
        void bind(IPEndPoint const& endpoint);
        void listen();
        void accept(Socket& socket);

        void close();

        UInt32 receive(void* buffer, UInt32 length);
        UInt32 receive(void* buffer, UInt32 length, IPEndPoint const& endpoint);

        UInt32 send(void const* buffer, UInt32 length);
        UInt32 send(void const* buffer, UInt32 length, IPEndPoint const& endpoint);

    private:
        Socket(Socket const& copy);
        Socket& operator=(Socket const& copy);

    private:
        SocketHandle _handle;
        IPEndPoint _localEndPoint;
        IPEndPoint _remoteEndPoint;
        
        bool _blocking;
        bool _connected;
        bool _bound;
        UInt32 _receiveTimeout;
    };
}}

// -----------------------------------------------------------

#endif
